/**
 * errorHandler.js - 全局错误处理中间件
 * 
 * 这个中间件负责捕获应用程序中的所有错误，并将它们转换为适当的HTTP响应。
 * 它处理不同类型的错误，包括验证错误、数据库错误、未授权错误等。
 */

const logger = require('../utils/logger');
const { ApiError } = require('../utils/errors');

/**
 * 全局错误处理中间件
 * 
 * @param {Error} err - 捕获的错误对象
 * @param {Object} req - Express请求对象
 * @param {Object} res - Express响应对象
 * @param {Function} next - 下一个中间件函数
 */
const errorHandler = (err, req, res, next) => {
  // 默认错误状态码和消息
  let statusCode = 500;
  let message = '服务器内部错误';
  let errors = [];
  
  // 记录错误（简化日志）
  logger.error(`${req.method} ${req.path} - ${err.message}`, {
    error: err.message,
    ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
  });
  
  // 处理自定义API错误
  if (err instanceof ApiError) {
    statusCode = err.statusCode;
    message = err.message;
    errors = err.errors || [];
  } 
  // 处理Joi验证错误
  else if (err.name === 'ValidationError' && err.isJoi) {
    statusCode = 400;
    message = '请求参数验证失败';
    errors = err.details.map(detail => ({
      field: detail.path.join('.'),
      message: detail.message,
    }));
  } 
  // 处理Express验证器错误
  else if (err.name === 'ValidationError' && Array.isArray(err.errors)) {
    statusCode = 400;
    message = '请求参数验证失败';
    errors = err.errors.map(error => ({
      field: error.param,
      message: error.msg,
    }));
  } 
  // 处理MongoDB重复键错误
  else if (err.name === 'MongoError' && err.code === 11000) {
    statusCode = 409;
    message = '资源已存在';
    const field = Object.keys(err.keyValue)[0];
    errors = [{ field, message: `${field}已存在` }];
  } 
  // 处理JWT错误
  else if (err.name === 'JsonWebTokenError') {
    statusCode = 401;
    message = '无效的令牌';
  } 
  // 处理JWT过期错误
  else if (err.name === 'TokenExpiredError') {
    statusCode = 401;
    message = '令牌已过期';
  }
  
  // 发送简化后的错误响应
  const response = {
    status: 'error',
    message,
    ...(errors.length > 0 && { errors })
  };
  
  // 仅在开发环境包含更多调试信息
  if (process.env.NODE_ENV === 'development') {
    response.debug = {
      path: req.path,
      method: req.method,
      ...(statusCode === 404 && { requestedUrl: req.originalUrl })
    };
  }
  
  res.status(statusCode).json(response);
};

module.exports = errorHandler;